package request

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"math"
	"net/http"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"vector/tools"
)

// 接口返回值
type xfResult struct {
	RetCode   int    `json:"retCode"`
	Desc      string `json:"desc"`
	ErrorInfo string `json:"errorInfo"`
	Data      []Data `json:"data"`
}

// Data 目标数据结果集
type Data struct {
	KnowledgeId   string  `json:"knowledgeId"`
	KnowledgeName string  `json:"KnowledgeName"`
	ParamName     string  `json:"paramName"`
	Content       string  `json:"content"`
	Score         float64 `json:"score"`
	GroupName     string  `json:"groupName"`
	GroupId       string  `json:"groupId"`
}

// 结构体字段值映射获取
func (d *Data) structField(name string) any {
	v := reflect.ValueOf(d).Elem().FieldByName(name)
	if !v.IsValid() {
		panic(fmt.Sprintf("field %s not found in Data", name))
	}
	return v.Interface()
}

// 将结果拼接成一个字符串
func (d *Data) topString() string {
	var sb strings.Builder
	if len(tools.Config.Vector.Embedding.TopString) == 0 {
		sb.WriteString(fmt.Sprintf("原子内容##：%s\n原子名称##：%s\n知识名称##：%s\n\n", d.Content, d.ParamName, d.KnowledgeName))
	} else {
		// 遍历模板
		for _, fields := range tools.Config.Vector.Embedding.TopString {
			kv := strings.Split(fields, "_")
			if len(kv) != 2 {
				panic("params.json top-string is bad")
			}
			// 将字段首字母大写
			sb.WriteString(fmt.Sprintf("%s##：%v\n", kv[0], d.structField(strings.Title(kv[1]))))
		}
	}
	return sb.String()
}

type IflytekVector struct {
	topString    strings.Builder
	note         error
	accuracy     []float64
	accuracyAtom []string
	Data         []Data
}

// NewRequest 发送请求
func (i *IflytekVector) NewRequest(content, provinceName string) error {
	// 向量地址
	if tools.Config.Vector.Embedding.Address == "" {
		return fmt.Errorf("配置文件缺少向量地址")
	}

	// 读取默认请求参数
	var param = make(map[string]any)
	tools.MapCopy(param, tools.Config.Vector.Embedding.Body)

	// 设置省份code
	provinceCode, err := tools.Config.Account.GetProvinceCode(provinceName)
	if err != nil {
		return err
	}
	param["provinceId"] = provinceCode
	// 判断是否需要设置rangeId
	if _, ok := param["rangeId"]; ok {
		param["rangeId"] = provinceCode
	}

	// 拼接问题
	param["content"] = content

	// map to json string
	body, err := json.Marshal(param)
	if err != nil {
		return err
	}

	if !tools.Config.IsSimplePrint {
		fmt.Println(string(body))
	}

	// 发送请求
	// 实例化链接对象
	resp, err := http.Post(tools.Config.Vector.Embedding.Address, "application/json;charset=utf-8", bytes.NewBuffer(body))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// 读取响应消息体
	respBody, _ := io.ReadAll(resp.Body)

	// 响应结果序列化
	xf := new(xfResult)
	if err = json.Unmarshal(respBody, xf); err != nil {
		return err
	}
	// 分析响应结果
	if xf.RetCode != 200 {
		return fmt.Errorf(xf.ErrorInfo)
	} else {
		i.Data = xf.Data
	}
	return nil

}

// Calculation 计算准确率，输出top10
func (i *IflytekVector) Calculation(totalAtomNum int, topNIndexList []int, knwlgAtomRl map[string][]string) error {

	if i.note != nil {
		return i.note
	}

	// 获取要统计TOP几准确率
	topNAtom := make([][]string, len(topNIndexList))

	// 遍历向量结果
	for index, atomItem := range i.Data {
		// 截取原子内容
		if tools.Config.InterceptNum > 0 && tools.Config.InterceptNum < len(atomItem.Content) {
			atomItem.Content = atomItem.Content[:tools.Config.InterceptNum]
		}

		// 拼接top10
		i.topString.WriteString(fmt.Sprintf("TOP%d:\n%s\n", index+1, atomItem.topString()))

		// 判断命中原子个数
		if atoms, ok := knwlgAtomRl[atomItem.KnowledgeName]; ok {
			// 判断命中原子个数
			if tools.ContainsAndDelete(&atoms, atomItem.ParamName) {
				for j, th := range topNIndexList {
					if index < th {
						if topNAtom[j] == nil {
							topNAtom[j] = []string{}
						}
						topNAtom[j] = append(topNAtom[j], atomItem.ParamName)
					}
				}
			}
			knwlgAtomRl[atomItem.KnowledgeName] = atoms
		}
	}

	// 计算准确率
	for j, atomList := range topNAtom {
		if totalAtomNum != 0 {
			i.accuracy[j] = math.Round(float64(len(atomList))/float64(totalAtomNum)*100) / 100
		}
		i.accuracyAtom[j] = strings.Join(atomList, "，")
	}
	return nil
}

// Print 将结构体转换为指定map输出
func (i *IflytekVector) Print(totalAtomNum int, topNIndexList []int) map[string]any {
	result := map[string]any{
		"TOP 10": i.topString.String(),
		"提供原子数量": totalAtomNum,
		"备注":     i.note,
	}
	for j, v := range topNIndexList {
		result[fmt.Sprintf("命中原子名称_TOP%d", v)] = i.accuracyAtom[j]
		result[fmt.Sprintf("准确率_TOP%d", v)] = i.accuracy[j]
	}
	return result
}

// TopStringToXfData 将topN字符串转换为Data对象
func (i *IflytekVector) TopStringToXfData(topString, splitString string) error {
	// 处理默认分隔符
	if splitString == "" {
		splitString = "\n\nTOP"
	}

	var result []Data
	lines := strings.Split(topString, splitString)

	for _, lineGroup := range lines {
		data := &Data{} // 初始化一个空的Data指针
		linesInGroup := strings.Split(lineGroup, "\n")

		for _, line := range linesInGroup {
			switch {
			case strings.HasPrefix(line, "知识名称##："):
				data.KnowledgeName = tools.TrimLine(line, "知识名称##：")
			case strings.HasPrefix(line, "原子名称##："):
				data.ParamName = tools.TrimLine(line, "原子名称##：")
			case strings.HasPrefix(line, "原子组名##："):
				data.GroupName = tools.TrimLine(line, "原子组名##：")
			case strings.HasPrefix(line, "原子内容##："):
				data.Content = tools.TrimLine(line, "原子内容##：")
			case strings.HasPrefix(line, "原子组内容##："):
				data.Content = tools.TrimLine(line, "原子组内容##：")
			}
		}

		// 检查必要的字段是否为空
		if data.KnowledgeName == "" || data.GroupName == "" || data.Content == "" {
			continue
		}

		result = append(result, *data)
	}

	i.Data = result

	return nil
}

// KnowledgeFormat 格式化知识格式
func KnowledgeFormat(knowledge, atoms string, isGroup bool) map[string][]string {
	// 格式化knowledgeListString
	knowledgeList := map[string][]string{}
	// 判断是否是原子组
	if isGroup {
		/*
			知识标题：标题1
			原子组名称：原子组名称1/原子组名称2

			知识标题：标题2
			原子组名称：原子组名称1
		*/
		for _, knowledgeString := range strings.Split(knowledge, "\n\n") {
			if knowledgeString == "" {
				continue
			}
			var knowledgeName string
			var groupNameList []string
			for _, line := range strings.Split(knowledgeString, "\n") {
				if line == "" {
					continue
				}

				keyValue := regexp.MustCompile(`[：:]+`).Split(line, -1)
				if len(keyValue) != 2 {
					continue
				}

				switch strings.TrimSpace(keyValue[0]) {
				case "知识标题", "知识名称":
					knowledgeName = strings.TrimSpace(keyValue[1])
				case "原子组名称", "原子名称":
					for _, gpn := range strings.Split(strings.TrimSpace(keyValue[1]), "/") {
						if gpn = strings.TrimSpace(gpn); gpn != "" {
							groupNameList = append(groupNameList, gpn)
						}
					}
				}
			}
			if knowledgeName != "" {
				knowledgeList[knowledgeName] = groupNameList
			}
		}
	} else {
		// 编译正则表达式：匹配数字开头后跟顿号或点号，以及可能跟随的空白符
		re := regexp.MustCompile(`^\d+[、.]\s*`)
		// 判断并去除序号前缀
		removeSerialPrefix := func(s string) string {
			// 查找匹配位置
			loc := re.FindStringIndex(s)
			if loc == nil {
				return s // 无序号前缀，返回原字符串
			}

			// 去除匹配到的前缀
			result := strings.TrimSpace(s[loc[1]:])
			return strings.TrimSpace(result)
		}
		// 整理知识名称
		var knowledgeNames []string
		for _, knowledgeName := range strings.Split(knowledge, "\n") {
			// 去除前面的序号 去除前后空格
			knowledgeName = removeSerialPrefix(knowledgeName)
			if knowledgeName != "" {
				knowledgeNames = append(knowledgeNames, knowledgeName)
			}
		}

		// 整理原子
		var atomList []string
		for _, atom := range strings.Split(atoms, "\n") {
			// 判断原子名称前是否有序号
			atom = removeSerialPrefix(atom)
			if strings.HasPrefix(atom, "Q&A") {
				atom = "问题"
			}
			if atom != "" {
				atomList = append(atomList, atom)
			}
		}

		// 匹配关系
		for index, knowledgeName := range knowledgeNames {
			// 知识原子个数对不上，直接将所有原子赋予每个人知识
			if len(atomList) != len(knowledgeNames) {
				knowledgeList[knowledgeName] = atomList
			} else {
				// 对应赋值原子
				knowledgeList[knowledgeName] = strings.Split(atomList[index], "||")
			}
		}
		knowledgeList["total"] = []string{strconv.Itoa(len(atomList))}
	}

	return knowledgeList
}
